組員:10170165 楊淳光 10170414 許凱勛

1 摘要

本報告涵蓋了一系列交易策略的開發、優化和效能評估,以及建立一個基於 Shiny 的互動式應用程式的過程。

  • 不同的交易策略在不同市場條件下表現可能不同,沒有一種策略適用於所有情況

  • 參數最佳化可以顯著提高策略的效能,但需要謹慎選擇參數範圍

  • 互動式Shiny應用程式為交易策略的快速測試和比較提供了便利。

本報告總結了交易策略的開發和優化過程,以及創建Shiny應用程式的步驟。


交易策略的選擇應基於市場狀況和個人偏好,並且需要定期監控和調整以適應不斷變化的市場條件。


Shiny應用程式為交易者提供了一個有用的工具,用於測試和比較不同策略,以支援更好的投資決策。


2 策略介紹

2.1 策略概述

我們志在綜合各交易策略對2022年台灣股市的分析,專注於食品、生技醫療、半導體、觀光餐旅四個產業,目標是最大化利潤(勝率和收利率)並控制風險


2.2 策略步驟

2.2.1 個別面

單獨使用所學過的交易策略,由於課堂上已有範例,個這邊不多作介紹。

這邊先重新run過一遍老師所教的交易策略並調整最佳參數,以看出在其中有無特殊,例如:產業間參數設定不同,交易指逼間的互相調和與搭配…,藉由一步一步地去看出最佳搭配結果以得出最優買賣時機。


2.2.2 移動平均&動量面:

經過個別面之後,我們先選擇合併myMom和myMA的兩個交易策略,看這樣共同使用會不會使我們的勝率提升,平均勝收益率上升,平均輸收益率下降

結果:我們嘗試創意過後,發現勝率由0.4->0.462

平均勝收益率0.00306->0.0036

平均輸收益率-0.00351->-0.0029

可以看出只用單一策略時勝收益<輸收益,這要是虧錢的交易策略

當我們合併動量和MA兩個策略的時候,收益變動上由勝收益>輸收益,這樣的策略符合我們的預期,因此我們接著嘗試再結合更多策略去製作出更優化的策略。


2.2.3 整合面:

我們結合了以下方法,並透過不斷的優化過程和調整參數,已可以自動得出最佳結果。

策略函數:

  1. 動量交易策略 - myMom 函數
    1. 原理:動量策略是基於一個假設,即股票過去的表現趨勢會在未來持續。
    2. 實現:使用 momentum 函數來計算股票價格的變動率。 根據這個變化率,產生買進或賣出訊號。
  2. 基於RSI的交易策略 - myRSI 函數
    1. 原理:相對強弱指數(RSI)是衡量股票超買或超賣狀態的指標。
    2. 實現:計算短期RSI,並根據它們是否超過特定門檻來產生交易訊號。
    3. 缺點:因為RSI較容易出現假訊號,因此對於長期投資的人來說參考價值有限。
  3. 以移動平均線為基礎的交易策略 - myMA 函數
    1. 原理:移動平均線幫助確定股票的整體趨勢方向。
    2. 實現:比較短期(5)長期(20)移動平均線,當短期線超過長期線時發出買進訊號,反之則發出賣出訊號。
  4. 引進MACD作為技術指標 - myMACD 函數
    1. 原理:移動平均收斂發散(MACD)是一種,顯示兩條移動平均線之間的關係。

      此技術指標是由DIF(快)MACD(慢)兩條線組成的技術指標

    2. 實現:計算MACD指標,並根據其與訊號線的關係產生交易訊號。

    3. 缺點 : MACD其實為落後性指標,因此它的用法相較於動量(領先指標)會比較像是確認市場趨勢

計算績效評估(perfTrade):

  • 功能:評估交易策略的表現,包括勝率、平均獲利和平均虧損。

綜合交易策略(trade_strategy):

  • 功能:整合前述所有交易策略,透過結合它們的訊號來決定最終的交易動作。

自動優化策略(optimize_strategy):

  • 功能:嘗試不同的參數組合,以找到提供最佳效能的策略配置。

2.3 專有名詞解釋

2.3.1 RSI

  • 相對強弱指數,用於判斷股價的超買或超賣狀態。

    RSI指標公式如何計算與如何判讀:

    A=一定期間上升幅度的合計。

    B=一定期間下跌幅度的合計。

    簡單來說,就是以一定期間的上下變動算出上升的比例。

    RSI值越大,表示在過去一段期間,上漲機率較大;相反的,RSI值越小,表示過去一段期間,下跌機率較大

    RSI值的範圍介於在0-100之間。RSI指標的原發明者Wilder他用RSI值的 70、30做區分,當RSI值等於或大於70時,表示價格被超買或高估;當RSI數值小於或等於30時,表示價格被超賣或低估。指數越高代表市場越活絡,指數越低代表市場越低迷。

    RSI 指標,通常數值會以 50 作為多空的區隔:

    • 當 RSI值 > 50:代表買方力道較強,近期為上漲趨勢。

    • 當 RSI值 < 50:代表賣方力道較強,近期為下跌趨勢。

    • 當 RSI值40<RSI<60:區間整理。

    RSI指標又被稱為「逆勢指標」

    RSI值>80,代表市場過熱,市場上已經交投熱絡,可能會反轉走下跌趨勢,或短線回檔機會增加。

    RSI值<20,代表市場過冷,股價或許已跌到谷底且交投低迷,可能會反轉為上漲趨勢,或短線反彈機會增加。

    RSI指標背離:

    「背離」指的是RSI數值的走勢變化和現行價格走勢不一致的狀況,通常暗示價格即將出現反轉,RSI指標發明者Wilder認為背離通常是一個可以做買賣訊號。

    主要分為兩種情況:下跌背離、上漲背離。

    RSI下跌背離:股價創近期新高,但同時期的RSI指標沒有創新高卻向下走,可以認為上漲力道已經逐漸轉弱,暗示未來價格較容易往下。

    RSI上漲背離:股價創新低,但同時期的RSI指標卻沒有跟著創新低而向上走,可以認為下跌力道已經逐漸減弱,暗示未來價格較容易往上。

    然而所有技術指標都只是價格簡化後的數值,市場未來走勢千變萬化,背離現象與行情反轉之間並非有著一定的關聯性存在,而背離也有可能出現一段時間後,價格才開始出現反轉,因此投資人需要搭配其他技術指標(KD、MACD、DMI、布林通道等)進一步確認進出場的時機點。

    RSI 指標鈍化:

    鈍化」指的是指標失去作用的現象發生。RSI 對於價格漲跌的反應非常敏感,因此當價格在一個長期趨勢時(連續上漲或是連續下跌),而RSI 就很容易處在超買或是超賣區,卻不會有預期的反轉,這時 RSI 失去作用,就會有所謂鈍化失真的現象發生,稱之為 RSI 指標的鈍化。

    當RSI值在很高位階時,即使價格再上漲,RSI值再往上的力道卻愈來愈和緩而產生鈍化的情形,在此時若價格下跌,RSI值的拉回力道相對要比一般情況來得大。同理,當RSI值在低位階時,就算行情再下跌,而RSI值再下行的力道,也會趨於和緩。

    RSI指標黃金交叉與死亡交叉:

    RSI指標的另一個判斷買進或賣出訊號的方式,當短期的RSI線向上突破長期的RSI線,兩線的交點稱為黃金交叉,表示短期上漲趨勢強度大於長期是買進訊號。反之,當短期的RSI線向下跌破長期的RSI線,稱為死亡交叉,表示短期內下跌的趨勢強度大於長期為賣出訊號。

    而交叉簡單來說就是一種投資人可以評估的買賣訊號:

  • 黃金交叉出現時,代表價格後續可能還會持續上漲一段時間,可以考慮買進。

  • 死亡交叉出現時,代表價格後續可能會持續下跌一段時間,則考慮賣出。

    RSI 交易策略

    • 計算長短期 RSI

    • 當短期指標大於 80(超買) 或 短期指標向下穿過長期指標(死亡交叉)時,為賣出訊號。

    • 當短期指標小於 20(超賣) 或 短期指標向上穿過長期指標(黃金交叉)時,為買入訊號。


2.3.2 SMA

  • 簡單移動平均,顯示股價的平均趨勢。

本節中將解說最基本的簡單移動平均線的計算方法。

所謂的移動平均線,正如其名稱所示,是算出一定期間的價格平均值,並將之連成的線圖。簡單移動平均乃合計n期間的收盤價,然後再除以n計算得出。計算時會計算最近的n期間,觀看該計算數值每一天的變動(日線)。

【表1/簡單移動平均的計算方法】

日期 開盤價(Open) 最高價(High) 最低價(Low) 收盤價(Close) 5SMA
第1天 106.15 106.69 105.84 106.54
第2天 106.48 106.88 106.36 106.74
第3天 106.75 106.95 106.65 106.67
第4天 106.67 107.15 106.66 106.97
第5天 106.97 107.97 106.95 107.96 106.97
第6天 107.96 108.64 107.82 108.36 107.34
第7天 108.28 108.94 108.24 108.86 107.76

表1中,計算的是5日期間的SMA(5SMA)。將5天的收盤值合計起來除以5,所得數值就標示在「5SMA」列。
| 從簡單移動平均線可一目瞭然掌握市場走勢!

移動平均線的目的,就是「透過取平均值讓價格變動平滑化」。這樣讓價格變動的走勢更為清楚。

這張圖為收盤價、SMA、WMA、EMA四個數線所組成的

以上為補充


2.3.3 Momentum Trading Strategy

根據慣性原則,如果證券價格上漲,那麼它可能會繼續上漲;相反,如果證券價格下跌,那麼它可能會繼續下跌。Jegadeesh和Titman(1993)的研究發現,資產股票組合的中期收益具有延續性,也就是說中期價格有一種連續變動的動量效應。因此,我們可以通過研究證券價格的動量來分析價格變化的趨勢,並制定交易策略以獲取收益。

2.3.3.1 股價動量的計算公式

動量指標=(現在的收盤價÷-n日以前的收盤價)×100

2.3.3.2 最間單的動量交易策略如下:

  • 動量為大於0,具備上漲動能,為策略的買入訊號。

  • 動量為小於0,具備下跌動能,為策略的賣出訊號。

2.3.3.3 評價方式

一個交易策略的評價,是用模擬的方式。故有幾點假設或觀念需要先釐清,才可作出適當的評價。如下:

  • 策略的交易訊號出現時(買入或賣出),是假設以訊號出現當天的收盤價在隔天買賣

    • 策略交易訊號的隔一天,才為真正買賣日期
  • 策略交易訊號的正確與否,則可以訊號隔天的收益率與訊號本身綜合衡量。

    • 買入訊號一般定為+1,賣出訊號一般定為-1

    • 收益率為正(上漲),是指當天收盤價相對於前一天收盤價上漲。

    • 收益率為負(下跌),是指當天收盤價相對於前一天收盤價下跌。

    • 買入訊號,

      • 隔天上漲。買入訊號×隔天收益率=隔天收益率>0。訊號正確。

      • 隔天下跌。買入訊號×隔天收益率=隔天收益率<0。訊號錯誤。

      • 策略的收益率=原收益率=買入訊號×隔天收益率

    • 賣出訊號,

      • 隔天上漲。賣出訊號×隔天收益率=−1×隔天收益率<0。訊號錯誤。

      • 隔天下跌。賣出訊號×隔天收益率=−1×隔天收益率>0。訊號正確。

      • 策略的收益率=−1×原收益率=賣出訊號×隔天收益率

    • 結論

      • 策略交易訊號∗隔天收益率>0。訊號正確

      • 策略交易訊號∗隔天收益率<0。訊號錯誤

      • 策略的收益率=策略交易訊號×隔天收益率

  • 單期收益率與累積收益率

    • 單期收益率

    • 累積收益率(k 期收益率),也就是這一段時間的單期收益率相乘。

  • 交易策略的收益率與累積收益率

策略的評價方式:

  • 策略的預測正確率與錯誤率

  • 策略的累積收益率與無策略時的累積收益率的比較

  • 策略預測正確時的收益率的分佈,策略預測錯誤時的收益率的分佈

    • 有時候可能正確率高,但累積收益率卻不理想

    • 這可能是預測正確時的收益較低,不足以彌補策略預測錯誤的損失


2.3.4 MACD

MACD是「Moving Average Convergence Divergence」的簡稱,翻譯為「平滑異同移動平均線」。震盪指標一般都是用來分析市場是否過熱,而MACD是為數不多卻也可以作為趨勢指標來使用的震盪指標。

本篇文章除了介紹OANDA獨有內容以外,還將介紹MACD的基本知識與使用方法、以及交易策略等。

  • MACD 的移動平均線的收斂與發散

    1. 兼具趨勢指標功能的震盪指標

      這個指標是以2條移動平均線(Moving Average)的收斂與發散(Convergence Divergence)作為指標。

    2. 顯示2條EMA的位置關係

      具有敏感反應K線變動的特性。

      【MACD的計算式】
      MACD=短期EMA-長期EMA
      訊號線=MACD的n日移動平均

    3. MACD的意義

  • MACD 的交易策略與使用方法

    MACD 指標 (Moving Average Convergence & Divergence) 中文名為平滑異同移動平均線指標,MACD 是在 1970 年代由美國人 Gerald Appel 所提出,是一項歷史悠久且經常在交易中被使用的技術分析工具,原理是利用快慢線的交錯,藉以判斷股價走勢的轉折。

    在 MACD 的技術分析中,最常用的值為 12 天、26 天、9 天,也稱為 MACD (12,26,9),市場常用 MACD 指標來判斷操作標的的後市走向確定波段漲幅並找到進、出場點

    當在計算 MACD 時,首先必須先計算長、短天期的「指數移動平均 (EMA)」,EMA 也是計算一定天期的平均價格,只是在計算上較近的日期會給予較高的權重;反之,較遠的日期則給予較低的權重,接著將長短天期EMA的相減,所得出差額就是「差離值 (DIF)」,代表短期 EMA 偏離長期 EMA 的情形。

    • 如何使用 MACD 找出買、賣點?

      綜合上述原理,故在使用 MACD 指標時,會 MACD 上有快線、慢線、柱狀圖這三個區塊。

      •快線 = 12 日 EMA – 26 日 EMA

      •慢線 = 快線取 9 日 EMA

      •柱狀圖 (直方圖) = 快線–慢線,EMA 快慢線相減後,所得差額即是 MACD 指標之柱狀圖。

      而由於柱狀圖即反應了快線與慢線的變化,因此使用 MACD 指標時可以直接簡化看柱狀圖,另外兩條線則是在判斷背離時才會用到。

      MACD 黃金交叉

      MACD 死亡交叉


3 策略評估方式

我們使用了以下準則:

3.1 動量交易策略 (myMom)

3.1.1 程式碼解釋

myMom <- function(Close, k) {
  Momen <- TTR::momentum(Close, n=k, na.pad=FALSE)
  signal <- ifelse(Momen < 0, -1, 1)
  
  ret <- TTR::ROC(Close, n=1, type="discrete")
  ret <- ret[-(1:k)]
  MomRet <- na.omit(ret * lag(signal, 1))
  
  return(list(tradeRet = MomRet))
}
  • 功能: 計算股價的動量,並基於此生成交易信號。

  • 策略過程:

    • 使用TTR::momentum計算股價的動量。

    • 若動量小於0,則賣出(信號為-1);若大於0,則買入(信號為1)

    • 計算股價的日收益率(TTR::ROC)。

    • 根據動量信號和日收益率計算交易的回報。

3.2 基於RSI的交易策略 (myRSI)

3.2.1 程式碼解釋

myRSI <- function(close, k_long=24, k_short=6, obLine=80, osLine=20) {
  rsi_l <- TTR::RSI(close, n=k_long, maType="SMA")
  rsi_s <- TTR::RSI(close, n=k_short, maType="SMA")
  
  obSig <- ifelse(rsi_s > obLine, -1, 0)
  osSig <- ifelse(rsi_s < osLine, 1, 0)
  
  rsi_s.lag <- lag(rsi_s, 1)
  rsi_l.lag <- lag(rsi_l, 1)
  RSIdata <- na.omit(merge(rsi_s, rsi_s.lag, rsi_l, rsi_l.lag))
  
  gcSig <- xts(apply(RSIdata, 1, function(x) ifelse((x[1] > x[3]) & (x[2] < x[4]), 1, 0)), order.by=index(RSIdata))
  dcSig <- xts(apply(RSIdata, 1, function(x) ifelse((x[1] < x[3]) & (x[2] > x[4]), -1, 0)), order.by=index(RSIdata))
  
  comboSig <- gcSig + dcSig
  
  return(list(comboTrade = comboSig))
}
  • 功能: 使用相對強弱指標(RSI)來判斷股票是否超買或超賣,從而生成交易信號。

  • 策略過程:

    • 分別計算長期和短期RSI。

    • 若短期RSI超過超買線(例如80),則賣出;若低於超賣線(例如20),則買入。

    • 結合長短期RSI生成交叉信號,用於決策。

3.3 基於移動平均線的交易策略 (myMA)

3.3.1 程式碼解釋

myMA <- function(close, k_long=24, k_short=6) {
  MA_l <- TTR::SMA(close, n=k_long)
  MA_s <- TTR::SMA(close, n=k_short)
  
  MA_s.lag <- lag(MA_s, 1)
  MA_l.lag <- lag(MA_l, 1)
  MAdata <- na.omit(merge(MA_s, MA_s.lag, MA_l, MA_l.lag))
  
  gcSig <- xts(apply(MAdata, 1, function(x) ifelse((x[1] > x[3]) & (x[2] < x[4]), 1, 0)), order.by=index(MAdata))
  dcSig <- xts(apply(MAdata, 1, function(x) ifelse((x[1] < x[3]) & (x[2] > x[4]), -1, 0)), order.by=index(MAdata))
  
  comboSig <- gcSig + dcSig
  
  return(list(comboTrade = comboSig))
}

3.4 MACD策略 (myMACD)

3.4.1 程式碼解釋

myMACD <- function(close) {
  macd <- MACD(close, nFast = 12, nSlow = 26, nSig = 9)
  sig <- ifelse(macd$macd > macd$signal, 1, -1)
  return(xts(sig, order.by = index(macd)))
}
  • 功能: 利用MACD(移動平均收斂散布指標)生成交易信號。

  • 策略過程:

    • 計算MACD值和其信號線。

    • 當MACD大於信號線時,生成買入信號當小於信號線時,生成賣出信號

3.5 性能評估函數 (perfTrade)

3.5.1 程式碼解釋

perfTrade <- function(signal, ret) {
  alignedData <- na.omit(merge(signal, ret))
  tradeRet <- alignedData[, 1] * alignedData[, 2]
  
  tradeWinRate <- sum(tradeRet > 0) / length(tradeRet)
  tradeMeanWin <- mean(tradeRet[tradeRet > 0], na.rm = TRUE)
  tradeMeanLoss <- mean(tradeRet[tradeRet < 0], na.rm = TRUE)
  
  return(c(winRate = tradeWinRate, meanWin = tradeMeanWin, meanLoss = tradeMeanLoss))
}
  • 功能: 計算交易策略的勝率、平均盈利和平均損失。

  • 策略過程:

    • 將交易信號和回報率對齊,計算每次交易的回報。

    • 計算整體交易的勝率、平均盈利和平均損失。

3.6 寫成交易策略函數

# 修改後的交易策略函數
trade_strategy <- function(symbol, start_date, end_date, k_mom, k_ma_long, k_ma_short) {
  getSymbols(symbol, src = "yahoo", from = start_date, to = end_date, auto.assign = TRUE)
  stock_data <- get(symbol)
  close <- Cl(stock_data)

  # 動量策略
  mom_signal <- ifelse(momentum(close, n = k_mom) < 0, -1, 1)

  # 移动平均策略
  ma_signal <- ifelse(SMA(close, n = k_ma_short) > SMA(close, n = k_ma_long), 1, -1)

  # 组合信號
  combined_signal <- mom_signal + ma_signal
  combined_signal[combined_signal == 0] <- NA
  combined_signal_lag <- lag(combined_signal, 1)
  combined_signal_lag <- combined_signal_lag[-1] # 移除第一個元素

  # 計算收益
  ret <- ROC(close, n = 1, type = "discrete", na.pad = FALSE)
  valid_indices <- !is.na(combined_signal_lag) & !is.na(ret)
  trade_ret <- ret[valid_indices] * combined_signal_lag[valid_indices]

  # 分類買入和賣出交易
  buy_trades <- trade_ret[combined_signal_lag[valid_indices] == 2]
  sell_trades <- trade_ret[combined_signal_lag[valid_indices] == -2]

  # 計算性能指標的函數
  calculate_performance <- function(trades) {
    if (length(trades) == 0) {
      return(c(0, 0, 0))
    }
    win_rate <- sum(trades > 0, na.rm = TRUE) / length(trades)
    mean_win <- mean(trades[trades > 0], na.rm = TRUE)
    mean_loss <- mean(trades[trades < 0], na.rm = TRUE)
    return(c(win_rate, mean_win, mean_loss))
  }

  # 應用函數並返回结果
  buy_performance <- calculate_performance(buy_trades)
  sell_performance <- calculate_performance(sell_trades)
  overall_performance <- calculate_performance(trade_ret)

  # 計算累計收益率
  cumulative_returns <- cumprod(1 + trade_ret) - 1

  return(list(
    buy_win_rate = buy_performance[1], buy_mean_win = buy_performance[2], buy_mean_loss = buy_performance[3],
    sell_win_rate = sell_performance[1], sell_mean_win = sell_performance[2], sell_mean_loss = sell_performance[3],
    overall_win_rate = overall_performance[1], overall_mean_win = overall_performance[2], overall_mean_loss = overall_performance[3],
    cumulative_returns = cumulative_returns
  ))
}

# 比較兩個性能结果,判斷新结果是否更好
is_better <- function(new_result, current_best) {
  # 您可以根據需要調整這些條件
  overall_better <- new_result$overall_win_rate > current_best$overall_win_rate &&
                    new_result$overall_mean_win > current_best$overall_mean_win &&
                    new_result$overall_mean_loss < current_best$overall_mean_loss

  buy_better <- new_result$buy_win_rate > current_best$buy_win_rate &&
                new_result$buy_mean_win > current_best$buy_mean_win &&
                new_result$buy_mean_loss < current_best$buy_mean_loss

  sell_better <- new_result$sell_win_rate > current_best$sell_win_rate &&
                 new_result$sell_mean_win > current_best$sell_mean_win &&
                 new_result$sell_mean_loss < current_best$sell_mean_loss

  return(overall_better && buy_better && sell_better)
}

3.7 自動嘗試得出結果

再來,讓函數自動嘗試不同的參數,並判斷捕捉最佳結果。

# 自動嘗試不同的參數
optimize_strategy <- function(symbol, start_date, end_date) {
  best_performance <- list(
    buy_win_rate = 0, buy_mean_win = 0, buy_mean_loss = Inf,
    sell_win_rate = 0, sell_mean_win = 0, sell_mean_loss = Inf,
    overall_win_rate = 0, overall_mean_win = 0, overall_mean_loss = Inf,
    params = NULL
  )

  for (k_mom in c(10, 20, 30)) {
    for (k_ma_long in c(20, 50, 100)) {
      for (k_ma_short in c(5, 10, 15)) {
        result <- trade_strategy(symbol, start_date, end_date, k_mom, k_ma_long, k_ma_short)
        
        # 更新最佳性能
        if (is_better(result, best_performance)) {
          best_performance <- list(
            buy_win_rate = result$buy_win_rate, buy_mean_win = result$buy_mean_win, buy_mean_loss = result$buy_mean_loss,
            sell_win_rate = result$sell_win_rate, sell_mean_win = result$sell_mean_win, sell_mean_loss = result$sell_mean_loss,
            overall_win_rate = result$overall_win_rate, overall_mean_win = result$overall_mean_win, overall_mean_loss = result$overall_mean_loss,
            params = c(k_mom, k_ma_long, k_ma_short)
          )
        }
      }
    }
  }

  return(best_performance)
}

這邊我們測試一下我們的優化策略,並繪製出累計收益率圖

# 測試優化策略
best_params <- optimize_strategy("2739.TW", "2022-01-01", "2022-12-31")
print(best_params)
## $buy_win_rate
## [1] 0.4117647
## 
## $buy_mean_win
## [1] 0.04181527
## 
## $buy_mean_loss
## [1] -0.02602993
## 
## $sell_win_rate
## [1] 0.2736842
## 
## $sell_mean_win
## [1] 0.01591191
## 
## $sell_mean_loss
## [1] -0.0186462
## 
## $overall_win_rate
## [1] 0.3388889
## 
## $overall_mean_win
## [1] 0.03077449
## 
## $overall_mean_loss
## [1] -0.02255523
## 
## $params
## [1] 10 20  5
# 創建累計收益率圖
plot_cumulative_returns <- function(cumulative_returns, title = "Cumulative Returns") {
  plot(cumulative_returns, type = "l", col = "blue", lwd = 2,
       xlab = "Time", ylab = "Cumulative Returns", main = title)
}

# 從best_params中提取参數
best_k_mom <- best_params$params[1]
best_k_ma_long <- best_params$params[2]
best_k_ma_short <- best_params$params[3]

# 使用這些参數調用交易策略函數
result <- trade_strategy("2739.TW", "2022-01-01", "2022-12-31", best_k_mom, best_k_ma_long, best_k_ma_short)
# 繪製累計收益率圖
plot_cumulative_returns(result$cumulative_returns)


4 股價回測

我們將展示使用過去數據的回測結果。

4.1 整體面

這邊以這11支股票在2022年做測試。分別為:

  • 食品:

    • 1216 統一

      ## $buy_win_rate
      ## [1] 0.4352941
      ## 
      ## $buy_mean_win
      ## [1] 0.01341549
      ## 
      ## $buy_mean_loss
      ## [1] -0.01624421
      ## 
      ## $sell_win_rate
      ## [1] 0.3764706
      ## 
      ## $sell_mean_win
      ## [1] 0.01445203
      ## 
      ## $sell_mean_loss
      ## [1] -0.01681969
      ## 
      ## $overall_win_rate
      ## [1] 0.4058824
      ## 
      ## $overall_mean_win
      ## [1] 0.0138962
      ## 
      ## $overall_mean_loss
      ## [1] -0.01653504
      ## 
      ## $params
      ## [1] 10 20  5

    • 1218 泰山

      ## $buy_win_rate
      ## [1] 0.4705882
      ## 
      ## $buy_mean_win
      ## [1] 0.04589791
      ## 
      ## $buy_mean_loss
      ## [1] -0.03667266
      ## 
      ## $sell_win_rate
      ## [1] 0.421875
      ## 
      ## $sell_mean_win
      ## [1] 0.03751953
      ## 
      ## $sell_mean_loss
      ## [1] -0.0334384
      ## 
      ## $overall_win_rate
      ## [1] 0.4535519
      ## 
      ## $overall_mean_win
      ## [1] 0.04317241
      ## 
      ## $overall_mean_loss
      ## [1] -0.03549024
      ## 
      ## $params
      ## [1] 10 20  5

    • 1234 黑松

      ## $buy_win_rate
      ## [1] 0.4262295
      ## 
      ## $buy_mean_win
      ## [1] 0.006403486
      ## 
      ## $buy_mean_loss
      ## [1] -0.008869967
      ## 
      ## $sell_win_rate
      ## [1] 0.4
      ## 
      ## $sell_mean_win
      ## [1] 0.01119869
      ## 
      ## $sell_mean_loss
      ## [1] -0.01105124
      ## 
      ## $overall_win_rate
      ## [1] 0.4088398
      ## 
      ## $overall_mean_win
      ## [1] 0.009513888
      ## 
      ## $overall_mean_loss
      ## [1] -0.01027029
      ## 
      ## $params
      ## [1] 10 20  5

  • 生技醫療:

    • 1707 葡萄王

      ## $buy_win_rate
      ## [1] 0.4216867
      ## 
      ## $buy_mean_win
      ## [1] 0.03470129
      ## 
      ## $buy_mean_loss
      ## [1] -0.02149371
      ## 
      ## $sell_win_rate
      ## [1] 0.4793388
      ## 
      ## $sell_mean_win
      ## [1] 0.01831094
      ## 
      ## $sell_mean_loss
      ## [1] -0.02567941
      ## 
      ## $overall_win_rate
      ## [1] 0.4558824
      ## 
      ## $overall_mean_win
      ## [1] 0.02447935
      ## 
      ## $overall_mean_loss
      ## [1] -0.0235329
      ## 
      ## $params
      ## [1] 10 20  5

    • 1701 中化

      ## $buy_win_rate
      ## [1] 0.4782609
      ## 
      ## $buy_mean_win
      ## [1] 0.05534329
      ## 
      ## $buy_mean_loss
      ## [1] -0.03666351
      ## 
      ## $sell_win_rate
      ## [1] 0.4315789
      ## 
      ## $sell_mean_win
      ## [1] 0.02415617
      ## 
      ## $sell_mean_loss
      ## [1] -0.01989356
      ## 
      ## $overall_win_rate
      ## [1] 0.4545455
      ## 
      ## $overall_mean_win
      ## [1] 0.04030009
      ## 
      ## $overall_mean_loss
      ## [1] -0.02805788
      ## 
      ## $params
      ## [1] 10 20  5

  • 半導體:

    • 2330 台積電

      ## $buy_win_rate
      ## [1] 0.4677419
      ## 
      ## $buy_mean_win
      ## [1] 0.03128746
      ## 
      ## $buy_mean_loss
      ## [1] -0.02658655
      ## 
      ## $sell_win_rate
      ## [1] 0.5524476
      ## 
      ## $sell_mean_win
      ## [1] 0.03492859
      ## 
      ## $sell_mean_loss
      ## [1] -0.03287092
      ## 
      ## $overall_win_rate
      ## [1] 0.5268293
      ## 
      ## $overall_mean_win
      ## [1] 0.03395088
      ## 
      ## $overall_mean_loss
      ## [1] -0.03066103
      ## 
      ## $params
      ## [1] 10 20  5

    • 3008 大立光

      ## $buy_win_rate
      ## [1] 0.4634146
      ## 
      ## $buy_mean_win
      ## [1] 0.04416873
      ## 
      ## $buy_mean_loss
      ## [1] -0.02874451
      ## 
      ## $sell_win_rate
      ## [1] 0.5104167
      ## 
      ## $sell_mean_win
      ## [1] 0.03868924
      ## 
      ## $sell_mean_loss
      ## [1] -0.03358576
      ## 
      ## $overall_win_rate
      ## [1] 0.488764
      ## 
      ## $overall_mean_win
      ## [1] 0.04108258
      ## 
      ## $overall_mean_loss
      ## [1] -0.03127772
      ## 
      ## $params
      ## [1] 10 20  5

    • 3443 創意

      ## $buy_win_rate
      ## [1] 0.4563107
      ## 
      ## $buy_mean_win
      ## [1] 0.05384093
      ## 
      ## $buy_mean_loss
      ## [1] -0.04480784
      ## 
      ## $sell_win_rate
      ## [1] 0.4375
      ## 
      ## $sell_mean_win
      ## [1] 0.07596976
      ## 
      ## $sell_mean_loss
      ## [1] -0.07548923
      ## 
      ## $overall_win_rate
      ## [1] 0.4480874
      ## 
      ## $overall_mean_win
      ## [1] 0.06328616
      ## 
      ## $overall_mean_loss
      ## [1] -0.05855055
      ## 
      ## $params
      ## [1] 10 20  5

  • 觀光餐旅:

    • 2727 王品

      ## $buy_win_rate
      ## [1] 0.45
      ## 
      ## $buy_mean_win
      ## [1] 0.04021962
      ## 
      ## $buy_mean_loss
      ## [1] -0.03250924
      ## 
      ## $sell_win_rate
      ## [1] 0.4166667
      ## 
      ## $sell_mean_win
      ## [1] 0.03727993
      ## 
      ## $sell_mean_loss
      ## [1] -0.03637379
      ## 
      ## $overall_win_rate
      ## [1] 0.4347826
      ## 
      ## $overall_mean_win
      ## [1] 0.0389335
      ## 
      ## $overall_mean_loss
      ## [1] -0.03432785
      ## 
      ## $params
      ## [1] 10 20  5

    • 2731 雄獅

      ## $buy_win_rate
      ## [1] 0.4519231
      ## 
      ## $buy_mean_win
      ## [1] 0.03998454
      ## 
      ## $buy_mean_loss
      ## [1] -0.03544487
      ## 
      ## $sell_win_rate
      ## [1] 0.5125
      ## 
      ## $sell_mean_win
      ## [1] 0.02882105
      ## 
      ## $sell_mean_loss
      ## [1] -0.03531791
      ## 
      ## $overall_win_rate
      ## [1] 0.4782609
      ## 
      ## $overall_mean_win
      ## [1] 0.03478337
      ## 
      ## $overall_mean_loss
      ## [1] -0.03539293
      ## 
      ## $params
      ## [1] 10 20  5

    • 2739 寒舍

      ## $buy_win_rate
      ## [1] 0.4117647
      ## 
      ## $buy_mean_win
      ## [1] 0.04181527
      ## 
      ## $buy_mean_loss
      ## [1] -0.02602993
      ## 
      ## $sell_win_rate
      ## [1] 0.2736842
      ## 
      ## $sell_mean_win
      ## [1] 0.01591191
      ## 
      ## $sell_mean_loss
      ## [1] -0.0186462
      ## 
      ## $overall_win_rate
      ## [1] 0.3388889
      ## 
      ## $overall_mean_win
      ## [1] 0.03077449
      ## 
      ## $overall_mean_loss
      ## [1] -0.02255523
      ## 
      ## $params
      ## [1] 10 20  5


5 策略優劣評價

5.1 優勢

  1. 多元化的技術指標: 結合了動量指標、相對強弱指數(RSI)、移動平均線和MACD,這種多元化可以捕捉不同市場條件下的交易信號。

  2. 參數優化: 透過多種不同的參數組合來尋找出最佳的交易策略,這有助於增強策略的適應性和盈利能力。

5.2 劣勢

  1. 過度優化的風險: 參數優化可能導致過度擬合歷史數據,使策略在真實交易中的表現不如預期,且技術指標基於歷史數據,可能無法有效應對市場的快速變化或非常規事件。

  2. 缺乏風險管理機制: 我們策略主要集中於信號生成和性能優化,且不夠成熟,這樣會無法顯示出明確的風險管理措施,如止損或資金管理等。

其實重要的是要根據具體的市場條件和個人風險偏好進行選擇和調整。


6 結論

6.1 總結

我們探索了多種股票交易策略,包括基於動量、RSI、移動平均線和MACD的策略。

透過結合這些策略並測試不同的參數配置,我們開發了一個自動最佳化流程,以尋找最佳的交易策略。

將此過程整合到 R Markdown 和 Shiny 應用中,為用戶提供了一個互動的平台來測試和優化他們的股票交易策略。


6.2 建議

完成了以上的交易策略,我們覺得實際股市交易是複雜且風險較高的,因此在應用這些策略時需要謹慎,並考慮到潛在的市場風險。


7 附錄

| 這裡額外製作期中報告未完成的時間序列分析。

7.0.1 時間序列分析

7.0.1.1 繪製基本ARIMA模型:

  1. 從網上獲取指定股票的數據。

  2. 進行簡單的時間序列分析。

7.0.2 我將以台積電(代碼 “2330.TW”)為例:

# 載入所需的套件
library(quantmod)
library(forecast)
library(TTR)
library(ggplot2)

# 抓取指定股票的數據
stockSymbol <- "2330.TW"
startDate <- "2022-01-01"
endDate <- "2023-01-01"
getSymbols(stockSymbol, src = "yahoo", from = startDate, to = endDate)
## [1] "2330.TW"
# 獲取收盤價
stockData <- get(stockSymbol)
closePrices <- Cl(stockData)

# 時間序列分析
# 計算簡單移動平均
sma <- SMA(closePrices, n = 20)

# 建立ARIMA模型
fit <- auto.arima(closePrices)
forecastedValues <- forecast(fit, h = 30)
summary(forecastedValues)
## 
## Forecast method: ARIMA(1,1,0)
## 
## Model Information:
## Series: closePrices 
## ARIMA(1,1,0) 
## 
## Coefficients:
##          ar1
##       0.0500
## s.e.  0.0645
## 
## sigma^2 = 99.31:  log likelihood = -910.42
## AIC=1824.84   AICc=1824.88   BIC=1831.84
## 
## Error measures:
##                      ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -0.7018255 9.924613 7.802028 -0.1506675 1.552565 0.9927275
##                      ACF1
## Training set -0.005291523
## 
## Forecasts:
##     Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 247       448.6250 435.8541 461.3959 429.0936 468.1565
## 248       448.6313 430.1134 467.1492 420.3106 476.9520
## 249       448.6316 425.7496 471.5136 413.6366 483.6266
## 250       448.6316 422.0929 475.1703 408.0441 489.2190
## 251       448.6316 418.8823 478.3809 403.1339 494.1292
## 252       448.6316 415.9859 481.2773 398.7043 498.5589
## 253       448.6316 413.3264 483.9368 394.6369 502.6263
## 254       448.6316 410.8536 486.4096 390.8551 506.4081
## 255       448.6316 408.5330 488.7302 387.3061 509.9571
## 256       448.6316 406.3396 490.9236 383.9515 513.3117
## 257       448.6316 404.2544 493.0088 380.7625 516.5007
## 258       448.6316 402.2629 495.0003 377.7168 519.5464
## 259       448.6316 400.3535 496.9097 374.7967 522.4665
## 260       448.6316 398.5168 498.7464 371.9877 525.2755
## 261       448.6316 396.7451 500.5181 369.2780 527.9852
## 262       448.6316 395.0319 502.2313 366.6579 530.6053
## 263       448.6316 393.3718 503.8914 364.1190 533.1442
## 264       448.6316 391.7601 505.5031 361.6542 535.6090
## 265       448.6316 390.1929 507.0703 359.2573 538.0059
## 266       448.6316 388.6666 508.5966 356.9230 540.3402
## 267       448.6316 387.1782 510.0850 354.6467 542.6165
## 268       448.6316 385.7250 511.5382 352.4242 544.8390
## 269       448.6316 384.3046 512.9586 350.2520 547.0112
## 270       448.6316 382.9149 514.3483 348.1266 549.1366
## 271       448.6316 381.5540 515.7092 346.0453 551.2179
## 272       448.6316 380.2202 517.0430 344.0054 553.2578
## 273       448.6316 378.9119 518.3513 342.0045 555.2587
## 274       448.6316 377.6277 519.6355 340.0405 557.2227
## 275       448.6316 376.3663 520.8969 338.1113 559.1518
## 276       448.6316 375.1265 522.1367 336.2153 561.0479
# 繪製股票收盤價和簡單移動平均線
plot(closePrices, main = paste("Stock Prices of", stockSymbol), col = "blue")

lines(sma, col = "red")

# 繪製ARIMA預測
autoplot(forecastedValues) + 
  ggtitle(paste("ARIMA Forecast for", stockSymbol)) + 
  ylab("Close Price")

這張圖展示了對台積電股票(2330.TW)的收盤價進行的 ARIMA(自迴歸整合移動平均)模型預測。從圖中可以看到:

1. 歷史數據:左側的黑色線條代表了歷史收盤價的時間序列數據。這是模型用來擬合和預測未來價格的基礎

2. 預測及置信區間:圖的右側展示了模型預測的未來價格,以及預測的不確定性。預測價格通常用一條線表示,而不確定性則通過置信區間來表示,這在圖中以藍色陰影展示。置信區間越寬,表示預測的不確定性越大。

3. 預測趨勢:預測顯示,模型預計股票價格會在預測期內呈現出一定的趨勢。然而,由於置信區間的存在,實際的價格可能會高於或低於預測線。

解讀這個預測時,要考慮到市場的許多不確定因素,這些因素可能會影響實際的價格走勢,而這些因素未必被模型充分考慮在內。
ARIMA模型主要是基於時間序列的過去行為來進行預測,它不考慮外部因素如經濟事件、行業發展或公司特定新聞等。因此,這種預測應該與其他分析一起使用,以獲得更全面的市場預測。


7.0.2.1 繪製指數平滑 (Exponential Smoothing)預測模型

模型解釋:

預測方法:使用的是ETS(A,N,N)模型,即指數平滑狀態空間模型,其中“A”代表加法誤差“N”代表沒有趨勢“N”代表沒有季節性

library(quantmod)
library(forecast)

# 設定股票代碼和抓取數據的日期範圍
stockSymbol <- '2330.TW'
startDate <- '2020-01-01'
endDate <- '2023-01-01'

# 從Yahoo Finance抓取數據
getSymbols(stockSymbol, src = 'yahoo', from = startDate, to = endDate)
## [1] "2330.TW"
stockData <- get(stockSymbol)
stockPrices <- Cl(stockData)

# 建立指數平滑模型
etsModel <- ets(stockPrices)

# 進行預測
futurePrices <- forecast(etsModel, h = 30)
summary(futurePrices)
## 
## Forecast method: ETS(A,N,N)
## 
## Model Information:
## ETS(A,N,N) 
## 
## Call:
##  ets(y = stockPrices) 
## 
##   Smoothing parameters:
##     alpha = 0.9999 
## 
##   Initial states:
##     l = 338.9729 
## 
##   sigma:  8.6721
## 
##      AIC     AICc      BIC 
## 8018.349 8018.382 8032.144 
## 
## Error measures:
##                     ME     RMSE      MAE        MPE     MAPE      MASE
## Training set 0.1492341 8.660295 6.541689 0.02170064 1.355492 0.9986584
##                   ACF1
## Training set 0.0695612
## 
## Forecasts:
##     Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 735       448.4997 437.3860 459.6135 431.5027 465.4968
## 736       448.4997 432.7833 464.2162 424.4635 472.5360
## 737       448.4997 429.2514 467.7481 419.0620 477.9375
## 738       448.4997 426.2739 470.7256 414.5082 482.4913
## 739       448.4997 423.6506 473.3489 410.4963 486.5032
## 740       448.4997 421.2790 475.7205 406.8692 490.1303
## 741       448.4997 419.0980 477.9015 403.5337 493.4658
## 742       448.4997 417.0680 479.9315 400.4291 496.5704
## 743       448.4997 415.1614 481.8381 397.5132 499.4863
## 744       448.4997 413.3581 483.6414 394.7552 502.2443
## 745       448.4997 411.6429 485.3566 392.1321 504.8674
## 746       448.4997 410.0041 486.9954 389.6257 507.3738
## 747       448.4997 408.4322 488.5673 387.2217 509.7778
## 748       448.4997 406.9197 490.0798 384.9086 512.0909
## 749       448.4997 405.4603 491.5392 382.6767 514.3228
## 750       448.4997 404.0489 492.9506 380.5180 516.4815
## 751       448.4997 402.6808 494.3187 378.4258 518.5737
## 752       448.4997 401.3525 495.6470 376.3943 520.6052
## 753       448.4997 400.0606 496.9389 374.4184 522.5811
## 754       448.4997 398.8022 498.1973 372.4939 524.5056
## 755       448.4997 397.5749 499.4246 370.6170 526.3825
## 756       448.4997 396.3766 500.6229 368.7842 528.2153
## 757       448.4997 395.2051 501.7944 366.9926 530.0069
## 758       448.4997 394.0589 502.9406 365.2396 531.7599
## 759       448.4997 392.9363 504.0632 363.5227 533.4768
## 760       448.4997 391.8359 505.1636 361.8399 535.1596
## 761       448.4997 390.7565 506.2430 360.1891 536.8104
## 762       448.4997 389.6969 507.3026 358.5686 538.4309
## 763       448.4997 388.6561 508.3434 356.9768 540.0227
## 764       448.4997 387.6330 509.3665 355.4122 541.5873

模型資訊:

  • 平滑參數

    • alpha = 0.9999表示觀測值對平滑值的影響非常大,幾乎接近1,表示模型對最近的觀測資料給予了幾乎全部的權重。
  • 初始狀態

    • l = 339.0158是模型的初始水平狀態。
  • 西格瑪

    • sigma: 8.4401是誤差項的標準差。
  • 資訊準則

    • AICAICcBIC是用於模型選擇的準則,較小的值表示模型複雜度和適合度之間有較好的平衡。

誤差度量:

  • 這些是模型在訓練集上的各種準確度測量。

    • ME(平均誤差)是0.2510417

    • RMSE(均方根誤差)是8.431395

    • MAE(平均絕對誤差)是6.315181

    • MPE(平均百分比誤差)是0.04089115%

    • MAPE(平均絕對百分比誤差)是1.279038%

    • MASE(平均絕對比例誤差)與簡單預測的相比是0.9989826,表示模型預測的準確度與簡單預測相當。

    • ACF1是殘差的一階自相關,0.04197816表示殘差中存在的自相關程度較低。

預測值:

  • 表格列出了未來一段時間內的預測值,點預測值在所有時間點上都是581.9995,表示模型預測未來的值將與最後一個觀測值相同。

  • Lo 80Hi 80為80%預測區間的下限和上限。

  • Lo 95Hi 95為95%預測區間的下限和上限。

這個模型的預測結果顯示,未來各時間點的預測值都保持不變,這是典型的平穩序列特徵。隨著預測期限的延長,預測區間也逐漸擴大,這反映了預測的不確定性隨著時間的推移而增加。

需要注意的是,股票市場預測充滿不確定性,實際未來價格可能會與預測值大不相同。ETS模型不考慮市場意外事件、市場條件變化或歷史價格變動以外的任何資訊。因此,投資決策應該基於全面的市場分析,並結合其他分析工具。

# 繪製預測圖表
plot(futurePrices)


7.0.2.2 差分整合移動平均模型 (ARIMA)

library(quantmod)
library(forecast)

# 設定股票代碼和抓取數據的日期範圍
stockSymbol <- '2330.TW'
startDate <- '2020-01-01'
endDate <- '2023-01-01'

# 從Yahoo Finance抓取數據
getSymbols(stockSymbol, src = 'yahoo', from = startDate, to = endDate)
## [1] "2330.TW"
stockData <- get(stockSymbol)
stockPrices <- Cl(stockData)

# 擬合ARIMA模型
arimaModel <- auto.arima(stockPrices)

# 進行預測
futurePrices <- forecast(arimaModel, h = 30)
summary(futurePrices)
## 
## Forecast method: ARIMA(0,1,0)
## 
## Model Information:
## Series: stockPrices 
## ARIMA(0,1,0) 
## 
## sigma^2 = 75.1:  log likelihood = -2622.94
## AIC=5247.88   AICc=5247.88   BIC=5252.48
## 
## Error measures:
##                     ME     RMSE      MAE        MPE     MAPE      MASE
## Training set 0.1496444 8.660243 6.542015 0.02182399 1.355599 0.9987081
##                    ACF1
## Training set 0.06946478
## 
## Forecasts:
##     Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 735          448.5 437.3939 459.6061 431.5147 465.4853
## 736          448.5 432.7936 464.2064 424.4791 472.5209
## 737          448.5 429.2636 467.7364 419.0805 477.9195
## 738          448.5 426.2878 470.7122 414.5293 482.4707
## 739          448.5 423.6660 473.3340 410.5196 486.4804
## 740          448.5 421.2957 475.7043 406.8946 490.1054
## 741          448.5 419.1160 477.8840 403.5610 493.4390
## 742          448.5 417.0872 479.9128 400.4582 496.5418
## 743          448.5 415.1817 481.8183 397.5440 499.4560
## 744          448.5 413.3794 483.6206 394.7876 502.2124
## 745          448.5 411.6652 485.3348 392.1660 504.8340
## 746          448.5 410.0273 486.9727 389.6611 507.3389
## 747          448.5 408.4563 488.5437 387.2585 509.7415
## 748          448.5 406.9447 490.0553 384.9467 512.0533
## 749          448.5 405.4862 491.5138 382.7161 514.2839
## 750          448.5 404.0755 492.9245 380.5586 516.4414
## 751          448.5 402.7083 494.2917 378.4677 518.5323
## 752          448.5 401.3807 495.6193 376.4373 520.5627
## 753          448.5 400.0896 496.9104 374.4626 522.5374
## 754          448.5 398.8319 498.1681 372.5393 524.4607
## 755          448.5 397.6054 499.3946 370.6634 526.3366
## 756          448.5 396.4077 500.5923 368.8317 528.1683
## 757          448.5 395.2369 501.7631 367.0412 529.9588
## 758          448.5 394.0914 502.9086 365.2892 531.7108
## 759          448.5 392.9694 504.0306 363.5733 533.4267
## 760          448.5 391.8697 505.1303 361.8914 535.1086
## 761          448.5 390.7909 506.2091 360.2416 536.7584
## 762          448.5 389.7320 507.2680 358.6220 538.3780
## 763          448.5 388.6917 508.3083 357.0311 539.9689
## 764          448.5 387.6693 509.3307 355.4675 541.5325
# 繪製預測圖表
plot(futurePrices)